<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1.0, user-scalable=no">
    <link rel="stylesheet" href="bootstrap/css/bootstrap.min.css">
    <title>学术家族树</title>
    <link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
    <script src="js/jquery.min.js"></script>
    <script src="bootstrap/js/bootstrap.min.js"></script>
    <link type="text/css" rel="stylesheet" href="type.css">
</head>

<body>
    <script src="js/d3.v3.min.js"></script>
    <div class="flex-container">
        <p id="title">家族树</p>
        <textarea type="textarea" id="text" cols="60" rows="10" class="center" placeholder="请输入内容"></textarea>
        <button href="javascript:;" onclick="getdata()" class="button_left">建立家族树</button>

    </div>
    <!--使用onclick触发下面的方法-->
    <script>
        var treeData = [{
            "name": "",
            "parent": "",
            "children": [{
                "name": "",
                "parent": "",
                "children": [{
                    "name": "",
                    "parent": ""
                }, {
                    "name": "",
                    "parent": "",
                    "children": [{
                        "name": "",
                        parent: ""
                    }]
                }, {
                    "name": "",
                    "parent": ""
                }, {
                    "name": "",
                    "parent": ""
                }]
            }, {
                "name": "",
                "parent": "",
                "children": [{
                    "name": "",
                    "parent": ""
                }, {
                    "name": "",
                    "parent": ""
                }, ]

            }, {
                "name": "",
                "parent": ""
            }, ]
        }];

        function getdata() {
            var text = $("#text").val(); //获取id为text的textarea的全部内容
            var text1 = text.split("\n\n");//针对多组数据输入的情况，以“\n\n"为关键字进行分组，调用split函数进行分割
            for (var k = 0; k < text1.length; k++) { //text1.length用于得到分组的数量
                var arry = text1[k].split("\n");//针对每一组数据，以“\n"为关键字进行分组，得到每条导师和学生的信息
                var teacher = {
                        name: '',
                        children: []
                    }

                for (var ii = 0; ii < arry.length; ii++) {
                    var newarr = arry[ii].split("：");//针对每条导师和学生的信息，以“：”为关键字进行分组，可得到身份标签和身份信息
                    var type = [];
                    var type1 = [];
                    var a1 = newarr[0]; //获取身份标签，如导师、2016级博士生等，保存在a1变量
                    if (ii != 0) {
                        type1.name = a1;
                    }
                    var a2 = newarr[1];//获取身份信息，如天一、王二、吴五等，保存在a2变量
                    var a3 = a2.split("、");//针对每组身份信息，以“、”为关键字进行切分，得到每个人的名字信息
                    for (var j = 0; j < a3.length; j++) { //a3.length用于得到每条身份信息里名字的数量

                        var student = {};
                        if (ii == 0) {
                            teacher.name = a3[j];
                        }
                        if (ii != 0) {
                            student.name = a3[j];
                            type.push(student);

                        }
                    }
                    if (ii != 0) {
                        type1.children = type;
                        teacher.children.push(type1);
                    }
                }

                treeData[k] = [];
                treeData[k] = teacher;
                maketree(k);
            }
        }

        function maketree(k) {
            var margin = {
                    top: 20,
                    right: 120,
                    bottom: 20,
                    left: 550,
                      
                },
                width = 960 - margin.right - margin.left ,
                height = 500 - margin.top - margin.bottom ;

            var i = 0,
                duration = 750, //过渡延迟时间
                root;

            var tree = d3.layout.tree() //创建一个树布局
                .size([height, width]);



            var diagonal = d3.svg.diagonal()
                .projection(function(d) {
                    return [d.y, d.x];
                }); //创建新的斜线生成器

            //声明与定义画布属性
            var svg = d3.select("body").append("svg")
                .attr("width", width + margin.right + margin.left)
                .attr("height", height + margin.top + margin.bottom)
                .append("g")
                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

            root = treeData[k]; //treeData为上边定义的节点属性
            root.x0 = height / 2;
            root.y0 = 0;


            update(root);


            function update(source) {
                // Compute the new tree layout.计算新树图的布局
                var nodes = tree.nodes(root).reverse(),
                    links = tree.links(nodes);

                // Normalize for fixed-depth.设置y坐标点，每层占180px
                nodes.forEach(function(d) {
                    d.y = d.depth * 180;
                });

                // Update the nodes…每个node对应一个group
                var node = svg.selectAll("g.node")
                    .data(nodes, function(d) {
                        return d.id || (d.id = ++i);
                    }); //data()：绑定一个数组到选择集上，数组的各项值分别与选择集的各元素绑定

                // Enter any new nodes at the parent's previous position.新增节点数据集，设置位置
                var nodeEnter = node.enter().append("g") //在 svg 中添加一个g，g是 svg 中的一个属性，是 group 的意思，它表示一组什么东西，如一组 lines ， rects ，circles 其实坐标轴就是由这些东西构成的。
                    .attr("class", "node") //attr设置html属性，style设置css属性
                    .attr("transform", function(d) {
                        return "translate(" + source.y0 + "," + source.x0 + ")";
                    })
                    .on("click", click);

                //添加连接点---此处设置的是圆圈过渡时候的效果（颜色）
                // nodeEnter.append("circle")
                //   .attr("r", 1e-6)
                //   .style("fill", function(d) { return d._children ? "lightsteelblue" : "#357CAE"; });//d 代表数据，也就是与某元素绑定的数据。
                nodeEnter.append("rect")
                    .attr("x", -23)
                    .attr("y", -10)
                    .attr("width", 70)
                    .attr("height", 20)
                    .attr("rx", 10)
                    .style("fill", "#800000"); //d 代表数据，也就是与某元素绑定的数据。


                nodeEnter.append("text")
                    .attr("x", function(d) {
                        return d.children || d._children ? 13 : 13;
                    })
                    .attr("dy", "10")
                    .attr("text-anchor", "middle")
                    .text(function(d) {
                        return d.name;
                    })
                    .style("fill", "white")
                    .style("fill-opacity", 1);
                // Transition nodes to their new position.将节点过渡到一个新的位置-----主要是针对节点过渡过程中的过渡效果
                //node就是保留的数据集，为原来数据的图形添加过渡动画。首先是整个组的位置
                var nodeUpdate = node.transition() //开始一个动画过渡
                    .duration(duration) //过渡延迟时间,此处主要设置的是圆圈节点随斜线的过渡延迟
                    .attr("transform", function(d) {
                        return "translate(" + d.y + "," + d.x + ")";
                    });

                nodeUpdate.select("rect")
                    .attr("x", -23)
                    .attr("y", -10)
                    .attr("width", 70)
                    .attr("height", 20)
                    .attr("rx", 10)
                    .style("fill", "#800000");

                nodeUpdate.select("text")
                    .attr("text-anchor", "middle")
                    .style("fill-opacity", 1);

                // Transition exiting nodes to the parent's new position.过渡现有的节点到父母的新位置。
                //最后处理消失的数据，添加消失动画
                var nodeExit = node.exit().transition()
                    .duration(duration)
                    .attr("transform", function(d) {
                        return "translate(" + source.y + "," + source.x + ")";
                    })
                    .remove();

                nodeExit.select("circle")
                    .attr("r", 1e-6);


                nodeExit.select("text")
                    .attr("text-anchor", "middle")
                    .style("fill-opacity", 1e-6);

                // Update the links…线操作相关
                //再处理连线集合
                var link = svg.selectAll("path.link")
                    .data(links, function(d) {
                        return d.target.id;
                    });


                // Enter any new links at the parent's previous position.
                //添加新的连线
                link.enter().insert("path", "g")
                    .attr("class", "link")
                    .attr("d", function(d) {
                        var o = {
                            x: source.x0,
                            y: source.y0
                        };
                        return diagonal({
                            source: o,
                            target: o
                        }); //diagonal - 生成一个二维贝塞尔连接器, 用于节点连接图.
                    })
                    .attr('marker-end', 'url(#arrow)');

                // Transition links to their new position.将斜线过渡到新的位置
                //保留的连线添加过渡动画
                link.transition()
                    .duration(duration)
                    .attr("d", diagonal);

                // Transition exiting nodes to the parent's new position.过渡现有的斜线到父母的新位置。
                //消失的连线添加过渡动画
                link.exit().transition()
                    .duration(duration)
                    .attr("d", function(d) {
                        var o = {
                            x: source.x,
                            y: source.y
                        };
                        return diagonal({
                            source: o,
                            target: o
                        });
                    })
                    .remove();

                // Stash the old positions for transition.将旧的斜线过渡效果隐藏
                nodes.forEach(function(d) {
                    d.x0 = d.x;
                    d.y0 = d.y;
                });
            }

            //定义一个将某节点折叠的函数
            // Toggle children on click.切换子节点事件
            function click(d) {
                if (d.children) {
                    d._children = d.children;
                    d.children = null;
                } else {
                    d.children = d._children;
                    d._children = null;
                }
                update(d);
            }
        }
        //d3.select(self.frameElement).style("height", "500px");
        // 定义菜单选项
        var userMenuData = [
            [{
                text: "添加",
                func: function() {
                    // id为节点id
                    var id = $(this).children("text").html();
                    id = id.substring(id.indexOf("(") + 1, id.indexOf(")"));
                    showDialog(id);
                }
            }, {
                text: "修改",
                func: function() {
                    var id = $(this).children("text").html();
                    id = id.substring(id.indexOf("(") + 1, id.indexOf(")"));
                    showEditDialog(id);
                }
            }, {
                text: "禁用",
                func: function() {
                    var id = $(this).children("text").html();
                    id = id.substring(id.indexOf("(") + 1, id.indexOf(")"));

                }
            }, {
                text: "删除",
                func: function() {
                    var id = $(this).children("text").html();
                    id = id.substring(id.indexOf("(") + 1, id.indexOf(")"));
                    deleteAppModule(id);
                }
            }]
        ];
        // 事件监听方式添加事件绑定
        $("g").smartMenu(userMenuData, {
            name: "chatRightControl",
            container: "g.node"
        });
    </script>
</body>

</html>